﻿
using SignalRApplication.Contracts;
using PoemGame.ApplicationService;
using PoemGame.Domain.GameAggregate;
using PoemGame.Domain.PlayerAggregate;
using PoemGame.UOW;


namespace SignalRApplication
{
    public class SignalRAppService : ISignalRAppService
    {
        private readonly IGameFactory gameFactory;
        private readonly IGamePlayServiceFactory gameServiceFactory;
        private readonly IGameRepository gameRepository;
        private readonly IPlayerRepository playerRepository;
        private readonly IUnitOfWorkManager unitOfWorkManager;

        public SignalRAppService(IGamePlayServiceFactory _gameServiceFactory,
            IGameRepository _gameRepository,
            IPlayerRepository _playerRepository,
            IGameFactory _gameFactory,
            IUnitOfWorkManager _unitOfWorkManager
            )
        {
            gameServiceFactory = _gameServiceFactory;
            gameRepository = _gameRepository;
            playerRepository = _playerRepository;
            gameFactory = _gameFactory;
            unitOfWorkManager = _unitOfWorkManager;
        }

        public async Task<string> AddPlayer(string playername, string nickname)
        {
            var player = new Player(Guid.Empty,playername, nickname,0);
            var id = await playerRepository.AddAsync(player);
            await unitOfWorkManager.Current.SaveChangesAsync();
            return id.ToString();
        }

        public async Task<bool> CheckPlayer(string playername)
        {
            var player = await playerRepository.GetPlayerByUserNameAsync(playername);
            return player != null;

        }

        public async Task<GameDetailDto> CreateGame(string playerName, string description, string gametype, string gamesubtype, bool inturn, string gamecontext)
        {
            var player = await playerRepository.GetPlayerByUserNameAsync(playerName);
            if (player == null) throw new Exception("用户不存在");
            var game = await gameFactory.CreateGame(player, new GameType(gametype, gamesubtype), inturn ? PlayType.Inturn : PlayType.FCFA, description, gamecontext);
            if (game.IsSuccess)
            {
                await gameRepository.AddAsync(game.CreatedGame);
                await unitOfWorkManager.Current.SaveChangesAsync();
                return await GetGameDetailDto(game.CreatedGame);
            }
            else throw new Exception(game.FaultReason.ToString());
        }

        public async Task GameOver(Guid gameguid)
        {
            var game = await gameRepository.GetAsync(gameguid);
            game.GameOver();
            await gameRepository.UpdateAsync(game);
            await unitOfWorkManager.Current.SaveChangesAsync();

        }

        public async Task<List<GameDto>> GetCanPlayGames(string playername)
        {
            var player = await playerRepository.GetPlayerByUserNameAsync(playername);
            if (player == null) throw new Exception("用户不存在");

            var lst = await gameRepository.GetByConditionAsync(o => (o.Status == GameStatus.Ready || o.Status == GameStatus.Running));
            var res = new List<GameDto>();
            foreach (var item in lst)
            {
                var playeringame = item.PlayersInGame.FirstOrDefault(o => o.PlayerId == player.Id);
                if (playeringame != null || item.Status == GameStatus.Ready)
                {
                    var gameType = "";
                    switch (item.GameType.MainType)
                    {
                        case "Feihualing":
                            gameType = "飞花令";
                            break;
                        case "Duishi":
                            gameType = "对诗";
                            break;
                        case "Jielong":
                            gameType = "接龙";
                            break;
                    }
                    res.Add(new GameDto
                    {
                        Id = item.Id,
                        Status =(int) item.Status,
                        Description = item.Description,
                        GameCondition = item.GameCondition,
                        PlayType = item.PlayType == PlayType.Inturn ? "轮流" : "抢答",
                        GameType = gameType
                    });
                }
            }
            return res;
        }

        public async Task<GameDetailDto> GetGame(Guid id)
        {
            var game = await gameRepository.GetAsync(id);
            return await GetGameDetailDto(game);
        }

        public async Task<PlayerDto> GetPlayerByUserName(string name)
        {
            var player= await playerRepository.GetPlayerByUserNameAsync(name);
            var dto = new PlayerDto { 
                Id= player.Id,
                NickName = player.NickName,
                UserName = player.UserName,
                Score=player.Score
            };
            return dto;
        }

        public async Task<List<GameDto>> GetPlayerGames(string playername)
        {
            var player = await playerRepository.GetPlayerByUserNameAsync(playername);
            if (player == null) throw new Exception("用户不存在");

            var lst = await gameRepository.GetAllAsync();
            var res = new List<GameDto>();
            foreach (var item in lst)
            {
                var playeringame = item.PlayersInGame.FirstOrDefault(o => o.PlayerId == player.Id);
                if (playeringame != null)
                {
                    var gameType = "";
                    switch (item.GameType.MainType)
                    {
                        case "Feihualing":
                            gameType = "飞花令";
                            break;
                        case "Duishi":
                            gameType = "对诗";
                            break;
                        case "Jielong":
                            gameType = "接龙";
                            break;
                    }
                    res.Add(new GameDto
                    {
                        Id = item.Id,
                        Status = (int)item.Status,
                        Description = item.Description,
                        GameCondition = item.GameCondition,
                        PlayType = item.PlayType == PlayType.Inturn ? "轮流" : "抢答",
                        GameType = gameType
                    });
                }
            }
            return res;
        }

        public async Task<string> JoinGame(string playername, Guid gameid)
        {
            var game = await gameRepository.GetAsync(gameid);
            var player = await playerRepository.GetPlayerByUserNameAsync(playername);
            if (player == null) return "用户不存在";
            var res = game.PlayerJoinGame(player);
            await gameRepository.UpdateAsync(game);
            await unitOfWorkManager.Current.SaveChangesAsync();
            return res.Message;
        }

        public async Task<string> LeaveGame(string playername, Guid gameid)
        {
            var game = await gameRepository.GetAsync(gameid);
            var player = await playerRepository.GetPlayerByUserNameAsync(playername);
            var res = game.PlayerLeaveGame(player);
            await gameRepository.UpdateAsync(game);
            await unitOfWorkManager.Current.SaveChangesAsync();
            return res.Message;
        }

        public async Task<string> PlayGame(string playername, Guid gameid, string answer)
        {
            var game = await gameRepository.GetAsync(gameid);
            var player = await playerRepository.GetPlayerByUserNameAsync(playername);
            var gameService = gameServiceFactory.GetGamePlayService(game.PlayType);
            var res = await gameService.GamePlay(player, game, answer);
            await unitOfWorkManager.Current.SaveChangesAsync();
            return res.Message;
        }

        public async Task RemoveGame(Guid gameid)
        {
            var game = await gameRepository.GetAsync(gameid);
            await gameRepository.RemoveAsync(game);
            await unitOfWorkManager.Current.SaveChangesAsync();
        }

        public async Task<string> SetAnswerPlayer(string playername, Guid gameid)
        {
            var game = await gameRepository.GetAsync(gameid);
            var player = await playerRepository.GetPlayerByUserNameAsync(playername);
            if (game == null) return "不存在游戏";
            if (game.Status != GameStatus.Running) return "游戏没有开始或已经结束";
            if (player == null) return "不存在玩家";

            var gameService = gameServiceFactory.GetGamePlayService(game.PlayType);

            var res = await gameService.SetPlayer(player, game);
            await gameRepository.UpdateAsync(game);
            await unitOfWorkManager.Current.SaveChangesAsync();
            return res.Message;
        }

        public async Task SetPlayerOut(string playername, Guid gameid)
        {
            var game = await gameRepository.GetAsync(gameid);
            var player = await playerRepository.GetPlayerByUserNameAsync(playername);
            game.SetPlayerOut(player.Id);
            player.DecreaseScore(10);//减十分
            //如果没有
            await playerRepository.UpdateAsync(player);
            await gameRepository.UpdateAsync(game);
            await unitOfWorkManager.Current.SaveChangesAsync();
        }

        public async Task<string> StartGame(string playername, Guid gameid)
        {
            var game = await gameRepository.GetAsync(gameid);
            var player = await playerRepository.GetPlayerByUserNameAsync(playername);
            if (game == null) return "不存在游戏";
            if (game.Status != GameStatus.Ready) return "游戏已经开始或已经结束";
            if (player == null) return "不存在玩家";
            var playeringame = game.PlayersInGame.FirstOrDefault(o => o.PlayerId == player.Id);
            if (playeringame == null) return "玩家不在游戏中";
            if (!playeringame.IsCreator) return "只有创建游戏的玩家才能启动游戏";
            var players = game.PlayersInGame;
            if (players.Count() < 2) return "至少有两个玩家加入才能启动游戏";

            game.Start();
            //var res= await gameService.GameStart(player, game);
            await gameRepository.UpdateAsync(game);
            await unitOfWorkManager.Current.SaveChangesAsync();
            return "游戏开始";
        }

        private async Task<GameDetailDto> GetGameDetailDto(Game game)
        {
            var dto = new GameDetailDto
            {
                Description = game.Description,
                Id = game.Id,
                Status = (int)game.Status,
                PlayType = game.PlayType == PlayType.Inturn ? "轮流" : "抢答",
                GameCondition = game.GameCondition
            };

            switch (game.GameType.MainType)
            {
                case "Feihualing":
                    dto.GameType = "飞花令";
                    break;
                case "Duishi":
                    dto.GameType = "对诗";
                    break;
                case "Jielong":
                    dto.GameType = "接龙";
                    break;
            }
            var currentplayer = game.GetCurrentPlayer();
            if (currentplayer != null)
            {
                dto.CurrentPlayer = (await playerRepository.GetPlayerByIdAsync(currentplayer.PlayerId)).UserName;
            }

            var creator = game.GetCreator();
            if (creator != null)
            {
                dto.Creator = (await playerRepository.GetPlayerByIdAsync(creator.PlayerId)).UserName;
            }

            var winner = game.PlayersInGame.FirstOrDefault(p=>p.IsWinner);
            if(winner != null)
            {
                dto.Winner = (await playerRepository.GetPlayerByIdAsync(winner.PlayerId)).UserName;
            }

            foreach(var r in game.PlayRecords)
            {
                var rdto = new RecordDto
                {
                    Answer = r.Answer,
                    GameId = r.GameId,
                    IsProperAnswer = r.IsProperAnswer,
                    PlayDateTime = r.PlayDateTime,
                    PlayerId = r.PlayerId,
                    PlayerName = r.PlayerName
                };
                dto.Records.Add(rdto);
            }

            foreach(var p in game.PlayersInGame)
            {
                var pdto = new PlayerInGameDto
                {
                    PlayerId = p.PlayerId,
                    PlayerName = (await playerRepository.GetPlayerByIdAsync(p.PlayerId)).UserName,
                    PlayerStatus = p.PlayerStatus == PlayerGameStatus.Out ? "出局" : p.PlayerStatus == PlayerGameStatus.Inturn ? "轮到" : "等待"
                };
                dto.Players.Add(pdto);
            }

            return dto;
        }

        public async Task UpdateNickName(UpdateNickNameDto dto)
        {
            var p = await playerRepository.GetPlayerByIdAsync(Guid.Parse(dto.playerid));
            if (p != null)
            {
                p.ChangeNickName(dto.nickname);
                await playerRepository.UpdateAsync(p);
            }
        }


    }
}
